﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;
using ESpace;
using AMVInfoSpace;

namespace AMVCommander
{
    public partial class FormMain : Form
    {
        #region *** переменные ***************************************************

        AMV SelAmv { get { if (lv.SelectedIndices.Count == 0)return null; return AmvShowList[lv.SelectedIndices[0]]; } }

        List<PlayList> pl = new List<PlayList>(); // список плейлистов

        // формы
        ESpace.FormEditValue frmEdit = new ESpace.FormEditValue();

        FormSettings frmSettings = new FormSettings();
        FormBackup frmBackup = new FormBackup();
        FormAmvInfo frmAmvInfo = null;

        List<string> LastTags = new List<string>();

        #endregion *** переменные ***************************************************

        #region *** события формы ***************************************************

        public FormMain()
        {
            InitializeComponent();

            Gl.fPathDb = Application.StartupPath + "\\AMV.db";
            Gl.fPathDbTags = Application.StartupPath + "\\TagDirs.db";
            Gl.dPathLogs = Application.StartupPath + "\\Logs"; if (!Directory.Exists(Gl.dPathLogs)) Directory.CreateDirectory(Gl.dPathLogs);
            Gl.fPathUpdateLog = Gl.dPathLogs + "\\Update.log";
            Gl.fPathLog = Gl.dPathLogs + "\\Debug_" + DateTime.Now.ToString("yyyy_MM_dd") + ".log";

            Gl.dPathPls = Application.StartupPath + "\\PlayLists\\"; if (!Directory.Exists(Gl.dPathPls)) Directory.CreateDirectory(Gl.dPathPls);
            Gl.dPathBackup = Application.StartupPath + "\\Backup\\"; if (!Directory.Exists(Gl.dPathBackup)) Directory.CreateDirectory(Gl.dPathBackup);
            Gl.dPathHistory = Application.StartupPath + "\\Backup\\Hist\\"; if (!Directory.Exists(Gl.dPathHistory)) Directory.CreateDirectory(Gl.dPathHistory);
            Gl.dPathTools = Application.StartupPath + "\\Tools"; if (!Directory.Exists(Gl.dPathTools)) Directory.CreateDirectory(Gl.dPathTools);
            Gl.dPathAmvInfo = Application.StartupPath + "\\AMVInfo"; if (!Directory.Exists(Gl.dPathAmvInfo)) Directory.CreateDirectory(Gl.dPathAmvInfo);

            // настройки
            Gl.Sett = new Settings(Gl.fPathSettings = Application.StartupPath + "\\Settings.stngs");
            RefillColumns();

            spnlMain.Panel1MinSize = 350;
            spnlMain.Panel2MinSize = 350;
            spnlMain.SplitterDistance = 350;

            // плейлисты
            String[] fl = Directory.GetFiles(Gl.dPathPls, "*.amvpl");
            for (int i = 0; i < fl.Length; i++)
                pl.Add(new PlayList(fl[i], true));

            // определение положения формы
            Rectangle rect = Screen.PrimaryScreen.WorkingArea;
            rect.Width -= 100;
            rect.Height -= 100;
            if (Gl.Sett.Frm_Top < rect.Top ||
                Gl.Sett.Frm_Left < rect.Left ||
                Gl.Sett.Frm_Top > rect.Bottom ||
                Gl.Sett.Frm_Left > rect.Right ||
                Gl.Sett.Frm_Width < MinimumSize.Width ||
                Gl.Sett.Frm_Height < MinimumSize.Height)
            {
                //
            }
            else
            {
                StartPosition = FormStartPosition.Manual;
                Size = new Size(Gl.Sett.Frm_Width, Gl.Sett.Frm_Height);
                Location = new Point(Gl.Sett.Frm_Left, Gl.Sett.Frm_Top);

            }

            SetFltIco();

        }

        private void FormMain_Shown(object sender, EventArgs e)
        {
            LoadDB();
            if (!Backup.TodayBackupExsist()) Backup.SaveBackup(Action.None);
            tmrCheckNew.Start();
        }

        private void FormMain_ResizeEnd(object sender, EventArgs e)
        {
            SaveNewFormPos();
        }

        private void FormMain_Move(object sender, EventArgs e)
        {
            SaveNewFormPos();
        }

        void SaveNewFormPos()
        {
            if (WindowState == FormWindowState.Normal)
            {
                if (Gl.Sett.Frm_Top != Top || Gl.Sett.Frm_Left != Left || Gl.Sett.Frm_Width != Width || Gl.Sett.Frm_Height != Height)
                {
                    Gl.Sett.Frm_Top = Top;
                    Gl.Sett.Frm_Left = Left;
                    Gl.Sett.Frm_Width = Width;
                    Gl.Sett.Frm_Height = Height;
                    Gl.Sett.Save();
                }
            }
        }

        #endregion *** события формы ***************************************************

        #region *** события коммандера ***************************************************

        List<AMV> AmvShowList = new List<AMV>();

        private void lv_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
        {
            AMV amv = AmvShowList[e.ItemIndex];
            e.Item = amv.itm;

            /*cntCash++;
            Text = cntCash.ToString();*/
        }

        private void lv_CacheVirtualItems(object sender, CacheVirtualItemsEventArgs e)
        {
            //
        }

        private void lv_VirtualItemsSelectionRangeChanged(object sender, ListViewVirtualItemsSelectionRangeChangedEventArgs e)
        {
            //
        }

        private void lv_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (SelAmv != null) Gl.OpenAmv(SelAmv);
        }

        private void lv_ColumnWidthChanging(object sender, ColumnWidthChangingEventArgs e)
        {
            ((Column)lv.Columns[e.ColumnIndex].Tag).Width = e.NewWidth;
            Gl.Sett.Save();
        }

        private void lv_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            if (tBtnSortMode.Checked)
            {
                AMV.CompareMode sortM = AMV.CompareMode.Name;
                switch (((Column)lv.Columns[e.Column].Tag).Tp)
                {
                    case ColumnType.Name: sortM = AMV.CompareMode.Name; break;
                    case ColumnType.Rating: sortM = AMV.CompareMode.Rating; break;
                    case ColumnType.Tag: sortM = AMV.CompareMode.Tag; break;
                    case ColumnType.Len: sortM = AMV.CompareMode.Len; break;
                    case ColumnType.Author: sortM = AMV.CompareMode.Author; break;
                    case ColumnType.Music: sortM = AMV.CompareMode.Music; break;
                    case ColumnType.Anime: sortM = AMV.CompareMode.Anime; break;
                    case ColumnType.Awards: sortM = AMV.CompareMode.Awards; break;
                    case ColumnType.FPath: sortM = AMV.CompareMode.FPath; break;
                    case ColumnType.KeyWords: sortM = AMV.CompareMode.KeyWords; break;
                }

                if (AMV.CmprMode != sortM)
                {
                    AMV.CmprUp = true;
                    AMV.CmprMode = sortM;
                }
                else
                {
                    AMV.CmprUp = !AMV.CmprUp;
                    /* if (!AMV.CmprUp)
                     {
                         AMV.CmprUp = true;
                         AMV.CmprMode = AMV.CompareMode.Name;
                     }
                     else AMV.CmprUp = false;*/
                }
                ReFillAmv();
            }
            else
            {
                frmEdit.SetParams("", 200, null, "");
                if (frmEdit.ShowDialog(((Column)lv.Columns[e.Column].Tag).Flt, false))
                {
                    ((Column)lv.Columns[e.Column].Tag).Flt = (string)frmEdit.Value;
                    ReFillAmv();
                    SetFltIco();
                }
            }
        }

        private void lv_KeyDown(object sender, KeyEventArgs e)
        {
            e.SuppressKeyPress = e.KeyCode != Keys.Up && e.KeyCode != Keys.Down;
            if (lv.SelectedIndices.Count == 0) return;

            if (e.KeyCode == Keys.Enter)
            {
                lv_MouseDoubleClick(null, null);
            }

            // редактирование ключевых слов
            if (e.KeyCode == Keys.K)
            {
                FormEditList frm = new FormEditList();
                frm.Text = "Редактирование ключевых слов";
                if (frm.ShowDialog(SelAmv.KeyWords))
                {
                    Backup.SaveBackup(Action.EditKeyWords, "для AMV '" + SelAmv.Name + "'"); // бекап перед редактированием
                    Gl.DB.Save();

                    SelAmv.UpdateItm(lv.Columns);
                    ReFillAmv();
                }
            }

        }

        #endregion *** события коммандера ***************************************************

        #region *** Drag And Drop ******************************************************************

        private void lv_ItemDrag(object sender, ItemDragEventArgs e)
        {
            if (SelAmv == null) return;

            lv.DoDragDrop(lv.SelectedItems, DragDropEffects.Copy);
        }

        private void lv_DragEnter(object sender, DragEventArgs e)
        {
            if (SelAmv == null) { e.Effect = DragDropEffects.None; return; }

            int len = e.Data.GetFormats().Length - 1;
            int i;
            for (i = 0; i <= len; i++)
            {
                if (e.Data.GetFormats()[i].Equals("System.Windows.Forms.ListView+SelectedListViewItemCollection"))
                {
                    //The data from the drag source is moved to the target.	
                    e.Effect = DragDropEffects.Copy;
                }
            }
        }

        private void lbPls_DragEnter(object sender, DragEventArgs e)
        {
            if (ddlPls.SelectedIndex == -1 || SelAmv == null) { e.Effect = DragDropEffects.None; return; }

            bool bMoveAccess = false;
            foreach (int ind in lv.SelectedIndices) if (AmvShowList[ind].Stat == AMV.Status.Normal) { bMoveAccess = true; break; }
            if (!bMoveAccess) { e.Effect = DragDropEffects.None; return; }

            int len = e.Data.GetFormats().Length - 1;
            int i;
            for (i = 0; i <= len; i++)
            {
                if (e.Data.GetFormats()[i].Equals("System.Windows.Forms.ListView+SelectedListViewItemCollection"))
                {
                    //The data from the drag source is moved to the target.	
                    e.Effect = DragDropEffects.Copy;
                }
            }
        }

        private void lbPls_DragDrop(object sender, DragEventArgs e)
        {
            if (ddlPls.SelectedIndex != -1 && lv.SelectedIndices.Count > 0)
            {
                // смотрим, нет ли уже такого amv в листе
                int cntNotAddRecs = 0;
                int cntAmvForAdd = 0; // amv, которые можно добавлять (существующие и проверенные)
                foreach (int ind in lv.SelectedIndices)
                {
                    AMV addAmv = AmvShowList[ind];
                    if (addAmv.Stat != AMV.Status.Normal) continue;
                    cntAmvForAdd++;
                    bool bUnic = true;
                    PlayList pls = pl[ddlPls.SelectedIndex];
                    for (int i = 0; i < pls.Itm.Count; i++)
                        if (pls.Itm[i].MD5Len == addAmv.MD5Len)
                        {
                            bUnic = false;
                            cntNotAddRecs++;
                            break;
                        }

                    if (bUnic)
                    {
                        pls.Itm.Add(new PlayListItem(addAmv.MD5Len, addAmv.Name));
                        pls.Save();
                        ReDrawPl();
                    }
                }

                // сообщение о недобавленных записях
                if (cntNotAddRecs == lv.SelectedIndices.Count) MessageBox.Show("Такие AMV уже есть в плейлисте");
                else
                {
                    string mess = "";
                    if (cntAmvForAdd != lv.SelectedIndices.Count) mess = "Некоторые AMV небыли добавлены, так как их файлы не существуют или не проверены на соответствие";
                    if (cntNotAddRecs > 0)
                    {
                        if (mess != "")
                        {
                            mess += "\r\n";
                            if (cntNotAddRecs == cntAmvForAdd) mess += "Остальные AMV небыли добавлены, так как они уже есть в плейлисте";
                            else mess += "Некоторые AMV небыли добавлены, так как они уже есть в плейлисте";
                        }
                        else
                        {
                            mess += "Некоторые AMV небыли добавлены, так как они уже есть в плейлисте";
                        }
                    }
                    if (mess != "") MessageBox.Show(mess);
                }

            }
        }

        #endregion *** Drag And Drop ***************************************************************

        #region *** функции коммандера ***************************************************

        void RefillColumns()
        {
            lv.Columns.Clear();
            foreach (Column clm in Gl.Sett.ClmL)
            {
                if (!clm.Visible) continue;

                ColumnHeader clmn = new ColumnHeader(24);
                clmn.Text = clm.Name;
                clmn.Width = clm.Width;
                clmn.Tag = clm;

                if (clm.Tp == ColumnType.Len) clmn.TextAlign = HorizontalAlignment.Right;

                lv.Columns.Add(clmn);
            }

        }

        void ReFillAmv()
        {
            ReFillAmv(false, true);
        }

        /// <summary>перезаполнение списка с учетом фильтрации
        /// при изменении списка или при изменении параметров фильтрации
        /// <param name="ActAmvRowId">RowID текущго amv (если -1, выделенного amv текущего нет. Если выделеное amv не входит в фильтрацию, выделение снимается)</param>
        void ReFillAmv(bool bRefill, bool bSaveSelect)
        {
            try
            {
                // если сохранять выделение, запоминаем выделенные AMV
                List<string> md5LenSelectedRecs = new List<string>();
                if (bSaveSelect)
                {
                    foreach (int ind in lv.SelectedIndices) md5LenSelectedRecs.Add(AmvShowList[ind].MD5Len);
                }

                // для разового обновления
                List<AMV> tmpAmvShowList = new List<AMV>();

                // иконки столбцов
                for (int i = 0; i < lv.Columns.Count; i++)
                {
                    int imInd = ((Column)lv.Columns[i].Tag).Flt == "" ? 24 : 27;
                    switch ((lv.Columns[i].Tag as Column).Tp)
                    {
                        case ColumnType.Name: if (AMV.CmprMode == AMV.CompareMode.Name) imInd += AMV.CmprUp ? 1 : 2; break;
                        case ColumnType.Rating: if (AMV.CmprMode == AMV.CompareMode.Rating) imInd += AMV.CmprUp ? 1 : 2; break;
                        case ColumnType.Tag: if (AMV.CmprMode == AMV.CompareMode.Tag) imInd += AMV.CmprUp ? 1 : 2; break;
                        case ColumnType.Len: if (AMV.CmprMode == AMV.CompareMode.Len) imInd += AMV.CmprUp ? 1 : 2; break;
                        case ColumnType.Author: if (AMV.CmprMode == AMV.CompareMode.Author) imInd += AMV.CmprUp ? 1 : 2; break;
                        case ColumnType.Music: if (AMV.CmprMode == AMV.CompareMode.Music) imInd += AMV.CmprUp ? 1 : 2; break;
                        case ColumnType.Anime: if (AMV.CmprMode == AMV.CompareMode.Anime) imInd += AMV.CmprUp ? 1 : 2; break;
                        case ColumnType.Awards: if (AMV.CmprMode == AMV.CompareMode.Awards) imInd += AMV.CmprUp ? 1 : 2; break;
                        case ColumnType.FPath: if (AMV.CmprMode == AMV.CompareMode.FPath) imInd += AMV.CmprUp ? 1 : 2; break;
                        case ColumnType.KeyWords: if (AMV.CmprMode == AMV.CompareMode.KeyWords) imInd += AMV.CmprUp ? 1 : 2; break;
                    }
                    lv.Columns[i].ImageIndex = imInd;

                }

                if (bRefill)
                    for (int i = 0; i < Gl.DB.Count; i++)
                        Gl.DB[i].UpdateItm(lv.Columns);

                List<string> notEmptyTags = new List<string>();
                for (int i = 0; i < Gl.DB.Count; i++)
                {
                    bool tagInFilter;
                    if (RecInFlt(Gl.DB[i], out tagInFilter))
                    {
                        tmpAmvShowList.Add(Gl.DB[i]);
                    }

                    if (tagInFilter)
                    {
                        foreach (string recTag in Gl.DB[i].Tags)
                            if (!notEmptyTags.Contains(recTag))
                                notEmptyTags.Add(recTag);
                    }
                }

                EmptyTags = Gl.DB.GetAllTags();
                foreach (string notEmptyTag in notEmptyTags) if (EmptyTags.Contains(notEmptyTag)) EmptyTags.Remove(notEmptyTag);

                tmpAmvShowList.Sort();

                // выставляем новый список
                lv.VirtualListSize = tmpAmvShowList.Count;
                AmvShowList = tmpAmvShowList;
                lv.Refresh();

                lblLen.Text = AmvShowList.Count.ToString() + "\\" + Gl.DB.Count.ToString();

                int indEnsureVisible = -1;
                try
                {
                    // поиск выделенного элемента (после сортировки)
                    lv.SelectedIndices.Clear();
                    for (int i = 0; i < AmvShowList.Count; i++)
                    {
                        foreach (string md5LenSelectedAmv in md5LenSelectedRecs)
                        {
                            if (AmvShowList[i].MD5Len == md5LenSelectedAmv)
                            {
                                if (indEnsureVisible == -1) indEnsureVisible = i;
                                lv.SelectedIndices.Add(i);
                            }
                        }
                    }

                    if (indEnsureVisible != -1) AmvShowList[indEnsureVisible].itm.EnsureVisible();

                    //break;
                }
                catch (Exception ex)
                {
                    Gl.WriteLog("ОШИБКА установки выделенного элемента при перерисовке ", "SelectedIndex=" + indEnsureVisible.ToString() + " AmvShowList.Count=" + AmvShowList.Count.ToString(), ex);
                    Application.DoEvents();
                    System.Threading.Thread.Sleep(200);
                }


                // обновление иконок 
                UpdateIcoAmvList();

                ReFillInfo();

                ResetIcoAndColorTags();
            }
            catch (Exception ex) { Gl.WriteLog("ОШИБКА перезаполнения списка AMV", "AmvShowList.Count=" + AmvShowList.Count.ToString(), ex); }

        }

        void UpdateIcoAmvList()
        {
            int cntErr = 0;
            Exception FirstEx = null;
            int FirstI = -1;
            for (int i = 0; i < AmvShowList.Count; i++)
            {
                try
                {
                    int indIco = 0;

                    if (AmvShowList[i].Stat == AMV.Status.Normal) { AmvShowList[i].itm.ForeColor = Color.Black; indIco = 0; }
                    if (AmvShowList[i].Stat == AMV.Status.NotEqual) { AmvShowList[i].itm.ForeColor = Color.Gray; indIco = 8; }
                    if (AmvShowList[i].Stat == AMV.Status.NotExist) { AmvShowList[i].itm.ForeColor = Color.Gray; indIco = 16; }

                    if (AmvShowList[i].AMVNewsNum != -1 && AmvShowList[i].AkrossNum != -1 && AmvShowList[i].CreaConNum != -1) indIco += 7;
                    else if (AmvShowList[i].AkrossNum != -1 && AmvShowList[i].CreaConNum != -1) indIco += 6;
                    else if (AmvShowList[i].AMVNewsNum != -1 && AmvShowList[i].CreaConNum != -1) indIco += 5;
                    else if (AmvShowList[i].AMVNewsNum != -1 && AmvShowList[i].AkrossNum != -1) indIco += 4;
                    else if (AmvShowList[i].CreaConNum != -1) indIco += 3;
                    else if (AmvShowList[i].AkrossNum != -1) indIco += 2;
                    else if (AmvShowList[i].AMVNewsNum != -1) indIco += 1;

                    AmvShowList[i].itm.ImageIndex = indIco;
                }
                catch (Exception ex) { if (cntErr == 0)FirstEx = ex; cntErr++; FirstI = i; }
            }
            if (cntErr > 0)
            {
                /* Gl.WriteLog("ОШИБКА обновления иконок",
                     "AmvShowList.Count=" + AmvShowList.Count.ToString() +
                     " FirstI=" + FirstI.ToString() +
                     " Stat=" + AmvShowList[FirstI].Stat.ToString() +
                     " Всего ошибок=" + cntErr.ToString()
                     , FirstEx);*/
            }
        }

        bool RecInFlt(AMV amv, out bool TagInFilter)
        {
            TagInFilter = false;

            bool bFind = false;
            string genFlt = tTxbGeneralFlt.Text.Trim();
            if (genFlt != "")
            {
                    foreach (Column clm in Gl.Sett.ClmL)
                    {
                        if (clm.Tp != ColumnType.Len)
                            if (CellInFlt(amv, clm.Tp, genFlt)) { bFind = true; break; }
                    }
                if (!bFind) return false;
            }

            // общие фильтры
            bFind = false;
            if (tBtnShowOnlyNotExist.Checked || tBtnShowOnlyNotEqual.Checked || tBtnShowOnlyAMVNews.Checked || tBtnShowOnlyAkross.Checked || tBtnShowOnlyCreaCon.Checked || tBtnShowOnlyNotLink.Checked)
            {
                if (tBtnShowOnlyNotExist.Checked && amv.Stat == AMV.Status.NotExist) bFind = true;
                if (tBtnShowOnlyNotEqual.Checked && amv.Stat == AMV.Status.NotEqual) bFind = true;
                if (tBtnShowOnlyAMVNews.Checked && amv.AMVNewsNum != -1) bFind = true;
                if (tBtnShowOnlyAkross.Checked && amv.AkrossNum != -1) bFind = true;
                if (tBtnShowOnlyCreaCon.Checked && amv.CreaConNum != -1) bFind = true;
                if (tBtnShowOnlyNotLink.Checked && amv.AMVNewsNum == -1 && amv.AkrossNum == -1 && amv.CreaConNum == -1) bFind = true;
                if (!bFind) return false;
            }

            // фильтры столбцов
            foreach (Column clm in Gl.Sett.ClmL)
            {
                if (!CellInFlt(amv, clm.Tp, clm.Flt)) return false;
            }

            // исключенные теги
            if (ExTags.Count > 0)
            {
                foreach (string exTag in ExTags)
                {
                    if (amv.Tags.Contains(exTag)) return false;
                }
            }

            // закрепленные теги (в записи должны быть все закрепленные теги. Иначе, возвращаем false)
            if (FixTags.Count > 0)
            {
                foreach (string fixTag in FixTags)
                {
                    if (!amv.Tags.Contains(fixTag)) return false;
                }
            }

            TagInFilter = true;

            // фильтр по выделенным тегам
            if (lvTags.SelectedItems.Count > 0)
            {
                bFind = false;
                List<TAG> selTags = GetAllSelectedTags();
                foreach (TAG selTag in selTags)
                {
                    if (amv.Tags.Contains(selTag.Name)) { bFind = true; break; }
                    if (bFind) break;
                }
                if (!bFind) return false;
            }

            return true;
        }

        bool CellInFlt(AMV amv, ColumnType Tp, string Flt)
        {
            string FLT = Flt.ToUpper();

            switch (Tp)
            {
                // Имя
                case ColumnType.Name:
                    {
                        if (FLT != "")
                        {
                            if (FLT == "<NULL>")
                            {
                                if (amv.Name.Trim() != "") return false;
                            }
                            else if (FLT == "<!NULL>")
                            {
                                if (amv.Name.Trim() == "") return false;
                            }
                            else if (amv.Name.ToUpper().IndexOf(FLT) == -1)
                                return false;
                        }
                        break;
                    }

                // рейтинг
                case ColumnType.Rating:
                    {
                        if (FLT != "")
                        {
                            if (FLT == "<NULL>")
                            {
                                if (amv.MiddleRating != 0) return false;
                            }
                            else if (FLT == "<!NULL>")
                            {
                                if (amv.MiddleRating == 0) return false;
                            }
                            else
                            {
                                if (FLT.StartsWith(">"))
                                {
                                    decimal val;
                                    if (!decimal.TryParse(FLT.Substring(1).Trim().Replace('.', ','), out val)) return false;
                                    if (amv.MiddleRating <= val) return false;
                                }
                                else if (FLT.StartsWith("<"))
                                {
                                    decimal val;
                                    if (!decimal.TryParse(FLT.Substring(1).Trim().Replace('.', ','), out val)) return false;
                                    if (amv.MiddleRating >= val) return false;
                                }
                                else return false;
                            }

                        }
                        break;
                    }

                // путь
                case ColumnType.FPath:
                    {
                        if (FLT != "")
                        {
                            if (FLT == "<NULL>")
                            {
                                if (amv.FLocalPath.Trim() != "") return false;
                            }
                            else if (FLT == "<!NULL>")
                            {
                                if (amv.FLocalPath.Trim() == "") return false;
                            }
                            else if (amv.FLocalPath.ToUpper().IndexOf(FLT) == -1)
                                return false;
                        }
                        break;
                    }

                // размер


                // автор
                case ColumnType.Author:
                    {
                        if (FLT != "")
                        {
                            if (FLT == "<NULL>")
                            {
                                if (amv.Atr.Count > 0) return false;
                            }
                            else if (FLT == "<!NULL>")
                            {
                                if (amv.Atr.Count == 0) return false;
                            }
                            else
                            {
                                if (amv.Atr.Count == 0) return false;
                                // если хотябы в одной строке есть совпадение, amv можно добавлять
                                bool bExist = false;
                                for (int j = 0; j < amv.Atr.Count; j++)
                                    if (amv.Atr[j].ToUpper().IndexOf(FLT) != -1)
                                    {
                                        bExist = true;
                                        break;
                                    }
                                if (!bExist) return false;
                            }
                        }
                        break;
                    }

                // музыка       
                case ColumnType.Music:
                    {
                        if (FLT != "")
                        {
                            if (FLT == "<NULL>")
                            {
                                if (amv.Msc.Count > 0) return false;
                            }
                            else if (FLT == "<!NULL>")
                            {
                                if (amv.Msc.Count == 0) return false;
                            }
                            else
                            {
                                if (amv.Msc.Count == 0) return false;
                                // если хотябы в одной строке есть совпадение, amv можно добавлять
                                bool bExist = false;
                                for (int j = 0; j < amv.Msc.Count; j++)
                                    if (amv.Msc[j].Name.ToUpper().IndexOf(FLT) != -1 || amv.Msc[j].Author.ToUpper().IndexOf(FLT) != -1)
                                    {
                                        bExist = true;
                                        break;
                                    }
                                if (!bExist) return false;
                            }
                        }
                        break;
                    }

                // аниме
                case ColumnType.Anime:
                    {
                        if (FLT != "")
                        {
                            if (FLT == "<NULL>")
                            {
                                if (amv.Anm.Count > 0) return false;
                            }
                            else if (FLT == "<!NULL>")
                            {
                                if (amv.Anm.Count == 0) return false;
                            }
                            else
                            {
                                if (amv.Anm.Count == 0) return false;
                                bool bExist = false;
                                for (int j = 0; j < amv.Anm.Count; j++)
                                    if (amv.Anm[j].ToUpper().IndexOf(FLT) != -1)
                                    {
                                        bExist = true;
                                        break;
                                    }
                                if (!bExist) return false;
                            }
                        }
                        break;
                    }

                // теги
                case ColumnType.Tag:
                    {
                        if (FLT != "")
                        {
                            if (FLT == "<NULL>")
                            {
                                if (amv.Tags.Count > 0) return false;
                            }
                            else if (FLT == "<!NULL>")
                            {
                                if (amv.Tags.Count == 0) return false;
                            }
                            else
                            {
                                if (amv.Tags.Count == 0) return false;
                                bool bExist = false;
                                for (int j = 0; j < amv.Tags.Count; j++)
                                    if (amv.Tags[j].ToUpper().IndexOf(FLT) != -1)
                                    {
                                        bExist = true;
                                        break;
                                    }
                                if (!bExist) return false;
                            }
                        }
                        break;
                    }

                // ключевые слова
                case ColumnType.KeyWords:
                    {
                        if (FLT != "")
                        {
                            if (FLT == "<NULL>")
                            {
                                if (amv.KeyWords.Count > 0) return false;
                            }
                            else if (FLT == "<!NULL>")
                            {
                                if (amv.KeyWords.Count == 0) return false;
                            }
                            else
                            {
                                if (amv.KeyWords.Count == 0) return false;
                                bool bExist = false;
                                for (int j = 0; j < amv.KeyWords.Count; j++)
                                    if (amv.KeyWords[j].ToUpper().IndexOf(FLT) != -1)
                                    {
                                        bExist = true;
                                        break;
                                    }
                                if (!bExist) return false;
                            }
                        }
                        break;
                    }

                // награды
                case ColumnType.Awards:
                    {
                        if (FLT != "")
                        {
                            if (FLT == "<NULL>")
                            {
                                if (amv.Awd.Count > 0) return false;
                            }
                            else if (FLT == "<!NULL>")
                            {
                                if (amv.Awd.Count == 0) return false;
                            }
                            else
                            {
                                if (amv.Awd.Count == 0) return false;
                                bool bExist = false;
                                for (int j = 0; j < amv.Awd.Count; j++)
                                    if (amv.Awd[j].ToUpper().IndexOf(FLT) != -1)
                                    {
                                        bExist = true;
                                        break;
                                    }
                                if (!bExist) return false;
                            }

                        }
                        break;
                    }
            }
            return true;
        }

        #endregion *** функции коммандера ***************************************************

        #region *** кнопки выпадающего меню коммандера ***************************************************

        private void mBtnEdit_Click(object sender, EventArgs e)
        {
            tmrCheckNew.Stop();
            if (lv.SelectedIndices.Count > 1) { int ind = lv.SelectedIndices[0]; lv.SelectedIndices.Clear(); lv.SelectedIndices.Add(ind); }
            FormEditAmv frmEditAmv = new FormEditAmv();

            if (frmEditAmv.ShowDialog(SelAmv, sender == mBtnTryParseFromAMVNews))
            {
                Backup.SaveBackup(Action.EditAmv);
                SelAmv.CopyFrom(frmEditAmv.resultAmv);
                Gl.DB.Save();

                SelAmv.UpdateItm(lv.Columns);

                // синхронизация базы тегов после редактирования
                Gl.SincTagDirs();
                RefillLvTags(true);
                ReFillAmv();
            }
            frmEditAmv.Dispose();
            tmrCheckNew.Start();
        }

        private void mBtnDel_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Вы действительно хотите удалить данные о AMV из базы?", "Удаление записи", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.No) return;

            if (File.Exists(SelAmv.FullPath) && SelAmv.Stat == AMV.Status.Normal)
            {
                System.Windows.Forms.DialogResult res = MessageBox.Show("ВНИМАНИЕ! Запись можно удалить вместе с ФАЙЛОМ на жестком диске. Вы действительно хотите удалить файл? (нет - удалиться только запись)",
                    "Удаление записи вместе с файлом", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2);
                if (res == System.Windows.Forms.DialogResult.Cancel) return;
                if (res == System.Windows.Forms.DialogResult.Yes) Gl.DeleteFileInRecycle(SelAmv.FullPath);
            }

            Backup.SaveBackup(Action.DelAmv);
            Gl.DB.Remove(SelAmv);
            Gl.DB.Save();

            AmvShowList.RemoveAt(lv.SelectedIndices[0]);
            lv.VirtualListSize = AmvShowList.Count;

            lv.SelectedIndices.Clear();
            lv.Refresh();

            // синхронизация базы тегов
            Gl.SincTagDirs();
            RefillLvTags(true);
            ResetIcoAndColorTags();
        }

        private void mBtnReplace_Click(object sender, EventArgs e)
        {
            opnReplaceFile.InitialDirectory = Gl.Sett.DPathHomeDir;
            if (opnReplaceFile.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                // считаем md5 файла
                String md5Len = Gl.GetMd5Len(opnReplaceFile.FileName);
                // сверяем с заменяемым
                if (md5Len == SelAmv.MD5Len) { MessageBox.Show("Нельзя заменить файл на самого себя"); return; }
                // смотрим, нет ли такого фаыла в базе вообще (чтобы исключить дубликаты)
                if (Gl.DB.IndexOfMD5(md5Len) != -1) { MessageBox.Show("Нельзя заменить файл, так как запись с таким файлом уже есть в базе"); return; }

                // заменяем файл на диске
                string dPath = SelAmv.FullPath.Substring(0, SelAmv.FullPath.LastIndexOf('\\'));
                // проверяем, существует ли директория.  если нет, предлагаем выбрать куда положить
                if (!Directory.Exists(dPath))
                {
                    MessageBox.Show("Каталога, в котором должен лежать файл более не существует. Выберете другой каталог");
                    selFldReplaceFile.SelectedPath = Gl.Sett.DPathHomeDir;
                    bool bSel = false; ;
                    while (!bSel)
                    {
                        if (selFldReplaceFile.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                        {
                            if (!selFldReplaceFile.SelectedPath.Contains(Gl.Sett.DPathHomeDir.Substring(0, Gl.Sett.DPathHomeDir.Length - 1)))
                            {
                                MessageBox.Show("Выбранный каталог лежит вне домашнего каталога");
                            }
                            else
                            {
                                dPath = selFldReplaceFile.SelectedPath;
                                bSel = true;
                            }
                        }
                        else return;
                    }
                }

                // заменяем путь к файлу, md5 и размер в базе
                SelAmv.FLocalPath = opnReplaceFile.FileName.Replace(Gl.Sett.DPathHomeDir, "");
                SelAmv.MD5Len = md5Len;
                SelAmv.Len = new FileInfo(SelAmv.FullPath).Length;
                SelAmv.Stat = AMV.Status.Normal;

                // сохраняем
                Gl.DB.Save();

                // обновляем item
                SelAmv.UpdateItm(lv.Columns);
                // обновляем список с новым статусом
                UpdateIcoAmvList();
                lv.Refresh();
            }
        }

        private void mBtnOpenOnAMVNews_Click(object sender, EventArgs e)
        {
            if (lv.SelectedIndices.Count > 1) { int ind = lv.SelectedIndices[0]; lv.SelectedIndices.Clear(); lv.SelectedIndices.Add(ind); }
            Gl.OpenOnAMVNews(SelAmv.AMVNewsNum);
        }

        private void mBtnOpenOnAkross_Click(object sender, EventArgs e)
        {
            if (lv.SelectedIndices.Count > 1) { int ind = lv.SelectedIndices[0]; lv.SelectedIndices.Clear(); lv.SelectedIndices.Add(ind); }
            Gl.OpenOnAkross(SelAmv.AkrossNum);
        }

        private void mBtnOpenOnCreaCon_Click(object sender, EventArgs e)
        {
            if (lv.SelectedIndices.Count > 1) { int ind = lv.SelectedIndices[0]; lv.SelectedIndices.Clear(); lv.SelectedIndices.Add(ind); }
            Gl.OpenOnCreaCon(SelAmv.CreaConNum);
        }

        private void mBtnOpenInTCmd_Click(object sender, EventArgs e)
        {
            if (lv.SelectedIndices.Count > 1) { int ind = lv.SelectedIndices[0]; lv.SelectedIndices.Clear(); lv.SelectedIndices.Add(ind); }
            Gl.OpenInTotalCommander(SelAmv.FullPath);
        }

        private void mAmvList_Opening(object sender, CancelEventArgs e)
        {
            if (SelAmv == null)
            {
                e.Cancel = true;
                return;
            }

            mBtnOpenOnAMVNews.Enabled = SelAmv.AMVNewsNum != -1;
            mBtnOpenOnAkross.Enabled = SelAmv.AkrossNum != -1;
            mBtnOpenOnCreaCon.Enabled = SelAmv.CreaConNum != -1;
            mBtnTryParseFromAMVNews.Enabled = SelAmv.IsPossableAMVNewsLink;
        }

        #endregion *** кнопки выпадающего меню коммандера ***************************************************

        #region *** кнопки верхнего меню ***************************************************

        private void tBtnChangeHomeDir_Click(object sender, EventArgs e)
        {
            opnFolder.SelectedPath = Gl.Sett.DPathHomeDir;
            if (opnFolder.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                Backup.SaveBackup(Action.NewHome);
                Gl.Sett.DPathHomeDir = opnFolder.SelectedPath + "\\";
                Gl.Sett.Save();

                // пробегаемся по и выставляем все файлы, как не существующие, даже, если не будет обновления
                for (int i = 0; i < Gl.DB.Count; i++)
                    Gl.DB[i].Stat = AMV.Status.NotExist;

                if (MessageBox.Show("Сделать поиск и добавление всех видеофайлов из новой домашней директории? Это может занять некоторое время в зависимости от объема данных.", "Обновление базы", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
                    UpdateHomeDir(false, false);
                else
                {
                    Gl.DB.Save();
                    ReFillAmv(true, false);
                }
            }
        }

        private void tBtnDelAll_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Вы действительно хотите очистить всю базу данных?", "Очищение всей базы данных", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
            {
                //System.Threading.Thread.Sleep(2000);
                if (MessageBox.Show("ВНИМАНИЕ!!! Данные невозможно будет восстановить.\r\nВсе равно настаиваете на полной очистке?", "Очищение всей базы данных", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == System.Windows.Forms.DialogResult.Yes)
                {
                    Backup.SaveBackup(Action.DellAll);
                    Gl.DB.Clear();
                    Gl.DB.Save();
                    ReFillAmv(true, false);
                }
            }
        }

        // обновление базы
        private void tBtnUpdate_Click(object sender, EventArgs e)
        {
            if (!Directory.Exists(Gl.Sett.DPathHomeDir))
            {
                MessageBox.Show("По текущему пути домашнего каталога больше не существует. Необходимо заново указать путь к домашнему каталогу");
                tBtnChangeHomeDir_Click(null, null);
                return;
            }

            if (MessageBox.Show("Сделать поиск, обновление и добавление всех видеофайлов домашней директории? Это может занять некоторое время в зависимости от объема данных.", "Обновление базы", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
            {
                Backup.SaveBackup(Action.Update);
                UpdateHomeDir(false, false);
            }
        }

        private void tBtnUpdateOnlyNew_Click(object sender, EventArgs e)
        {
            if (!Directory.Exists(Gl.Sett.DPathHomeDir))
            {
                MessageBox.Show("По текущему пути домашнего каталога больше не существует. Необходимо заново указать путь к домашнему каталогу");
                tBtnChangeHomeDir_Click(null, null);
                return;
            }

            if (MessageBox.Show("Сделать поиск, новых видеофайлов в домашней директории? Это может занять некоторое время в зависимости от объема данных.", "Обновление базы", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
            {
                Backup.SaveBackup(Action.Update);
                UpdateHomeDir(true, false);
            }
        }

        private void mBtnUpdateNotEqual_Click(object sender, EventArgs e)
        {
            if (!Directory.Exists(Gl.Sett.DPathHomeDir))
            {
                MessageBox.Show("По текущему пути домашнего каталога больше не существует. Необходимо заново указать путь к домашнему каталогу");
                tBtnChangeHomeDir_Click(null, null);
                return;
            }

            if (MessageBox.Show("Сделать поиск, новых видеофайлов в домашней директории? Это может занять некоторое время в зависимости от объема данных.", "Обновление базы", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
            {
                Backup.SaveBackup(Action.Update);
                UpdateHomeDir(false, true);
            }
        }

        #region *** Общие фильтры ****************************************************

        private void tBtnDelNotExist_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Действительно удалить все данные, для которых не найдены файлы AMV? Это может занять некоторое время в зависимости от объема данных.", "Удаление данных", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
            {
                Backup.SaveBackup(Action.DelNotEx);

                for (int i = 0; i < Gl.DB.Count; i++)
                {
                    if (Gl.DB[i].Stat == AMV.Status.NotExist)
                    {
                        Gl.DB.RemoveAt(i);
                        i--;
                    }
                }
                Gl.DB.Save();

                Gl.SincTagDirs();
                RefillLvTags(true);
                ReFillAmv();
            }
        }

        private void tBtnShowOnly_Click(object sender, EventArgs e)
        {
            SetFltIco();
            ReFillAmv();
        }

        private void tTxbGeneralFlt_TextChanged(object sender, EventArgs e)
        {
            tmrGeneralFlt.Stop();
            tmrGeneralFlt.Start();
        }

        private void tmrGenFlt_Tick(object sender, EventArgs e)
        {
            SetFltIco();
            ReFillAmv();
            tmrGeneralFlt.Stop();
        }

        private void tBtnClearFlt_Click(object sender, EventArgs e)
        {
            tBtnShowOnlyNotExist.Checked = false;
            tBtnShowOnlyNotEqual.Checked = false;
            tBtnShowOnlyAMVNews.Checked = false;
            tBtnShowOnlyAkross.Checked = false;
            tBtnShowOnlyCreaCon.Checked = false;
            tBtnShowOnlyNotLink.Checked = false;
            tBtnFlt.Image = Properties.Resources.flt_off;
            for (int i = 0; i < lv.Columns.Count; i++)
                ((Column)lv.Columns[i].Tag).Flt = "";
            lvTags.SelectedItems.Clear();
            ExTags.Clear();
            FixTags.Clear();
            EmptyTags.Clear();

            // удаление текста из общего фильтра автоматом обновит список AMV (если он есть)
            if (tTxbGeneralFlt.Text != "") tTxbGeneralFlt.Text = "";
            else ReFillAmv();

            SetFltIco();
        }

        #endregion *** Общие фильтры ****************************************************

        private void tBtnSettings_Click(object sender, EventArgs e)
        {
            frmSettings.ShowDialog();
            RefillColumns();
            ReFillAmv(true, true);
        }

        private void tBrnRestorDB_Click(object sender, EventArgs e)
        {
            if (frmBackup.ShowDialog(true))
            {
                LoadDB();
            }
        }

        private void tBtnFindDpl_Click(object sender, EventArgs e)
        {
            if (!File.Exists(Gl.dPathTools + "\\FindDuplicate\\FindDuplicates.exe")) return;
            Process.Start(Gl.dPathTools + "\\FindDuplicate\\FindDuplicates.exe");
        }

        private void tBtnCreateAMVInfo_Click(object sender, EventArgs e)
        {
            if (!File.Exists(Gl.dPathTools + "\\AMVNewsParser\\AMVNewsParser.exe")) return;
            Process.Start(Gl.dPathTools + "\\AMVNewsParser\\AMVNewsParser.exe");
        }

        private void tBtnOpenAllInPlayer_Click(object sender, EventArgs e)
        {
            PlayList pls = new PlayList("", false);
            // добавление всех видимых записей в плейлист
            foreach (AMV amv in AmvShowList) pls.Itm.Add(new PlayListItem(amv.MD5Len, amv.Name));
            OpenPl(pls, 0);
        }

        private void tBtnCreatePlsByAll_Click(object sender, EventArgs e)
        {
            Comm.EditValueShowForm("Создание плейлиста", "", new ConfirmClickDelegate(ConfirmAddPlsByAll_Click));
        }

        bool ConfirmAddPlsByAll_Click(string RetValue)
        {
            // добавление всех видимых записей в плейлист
            List<PlayListItem> plsItems = new List<PlayListItem>();
            foreach (AMV amv in AmvShowList) plsItems.Add(new PlayListItem(amv.MD5Len, amv.Name));
            return TryCreateNewPlayList(plsItems, RetValue);
        }

        #endregion *** кнопки верхнего меню ***************************************************

        #region *** плейлисты ************************************************

        void ReFillDdlPl(String selName)
        {
            ddlPls.Items.Clear();
            pl.Sort();
            int sel = -1;
            for (int i = 0; i < pl.Count; i++)
            {
                ddlPls.Items.Add(pl[i].Name);
                if (pl[i].Name == selName) sel = i;
            }
            ddlPls.SelectedIndex = sel;
        }

        bool ReDrawPl()
        {
            if (ddlPls.SelectedIndex == -1)
            {
                lbPls.Clear();
                return true;
            }
            PlayList p = pl[ddlPls.SelectedIndex];
            List<ESpace.EListBox.Item> sl = new List<ESpace.EListBox.Item>();
            int notExAmv = 0;
            for (int j = 0; j < p.Itm.Count; j++)
            {
                int ind = Gl.DB.IndexOfMD5(p.Itm[j].MD5Len);
                if (ind != -1)
                {
                    sl.Add(new ESpace.EListBox.Item((j + 1).ToString() + ". " + Gl.DB[ind].Name));
                }
                else
                {
                    notExAmv++;
                    ESpace.EListBox.Item itm = new ESpace.EListBox.Item(p.Itm[j].AddName);
                    itm.brText = new SolidBrush(Color.Red);
                    sl.Add(itm);
                }
            }
            lbPls.Refill(sl);
            if (notExAmv > 0)
            {
                return false;
            }
            return true;
        }

        private void ddlPls_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (!ReDrawPl()) MessageBox.Show("В плейлисте присутствуют amv, которые более не существуют в базе. Эти amv выделены красным");
            tBtnDelPls.Enabled = ddlPls.SelectedIndex != -1;
            tBtnEditPls.Enabled = ddlPls.SelectedIndex != -1;
        }

        private void lbPls_MoveItem(object Sender, int oldInd, int newInd)
        {
            PlayList pls = pl[ddlPls.SelectedIndex];
            PlayListItem c = pls.Itm[oldInd];
            pls.Itm.RemoveAt(oldInd);
            pls.Itm.Insert(newInd, c);
            pls.Save();
        }

        private void btnAddPls_Click(object sender, EventArgs e)
        {
            Comm.EditValueShowForm("Создание плейлиста", "", new ConfirmClickDelegate(ConfirmAddPls_Click));
        }

        bool ConfirmAddPls_Click(string RetValue)
        {
            String nm = ESpace.Comm.GetValidFileName(RetValue);
            if (nm == "") { MessageBox.Show("Плейлист небыл создан, так как в имени содержатся только недопустимые символы"); return false; }
            PlayList pls = new PlayList(nm, false);
            // проверка уникальности
            if (File.Exists(pls.FPath)) { MessageBox.Show("Такой плейлист уже существует"); return false; }

            if (tabControl1.SelectedTab != tabPagePalylists) tabControl1.SelectedTab = tabPagePalylists;
            pls.Save();
            pl.Add(pls);
            ReFillDdlPl(pls.Name);
            ReDrawPl();
            return true;
        }

        private void tBtnEditPls_Click(object sender, EventArgs e)
        {
            Comm.EditValueShowForm("Редактирование плейлиста", pl[ddlPls.SelectedIndex].Name, new ConfirmClickDelegate(ConfirmEditPls_Click));
        }

        bool ConfirmEditPls_Click(string RetValue)
        {
            return TryCreateNewPlayList(new List<PlayListItem>(), RetValue);
        }

        bool TryCreateNewPlayList(List<PlayListItem> plsItems, string plsName)
        {
            String nm = ESpace.Comm.GetValidFileName(plsName);
            if (nm == "") { MessageBox.Show("Плейлист небыл создан, так как в имени содержатся только недопустимые символы"); return false; }

            PlayList pls = new PlayList(nm, false);

            // проверка уникальности
            if (File.Exists(pls.FPath)) { MessageBox.Show("Такой плейлист уже существует"); return false; }

            pls.Itm = plsItems; // добавление записей

            if (tabControl1.SelectedTab != tabPagePalylists) tabControl1.SelectedTab = tabPagePalylists;
            pls.Save();
            pl.Add(pls);
            ReFillDdlPl(pls.Name);
            ReDrawPl();
            return true;
        }

        private void btnDelPls_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Действительно удалить плейлист?", "Удаление плейлиста", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
            {
                pl[ddlPls.SelectedIndex].Delete();
                pl.RemoveAt(ddlPls.SelectedIndex);
                ReFillDdlPl("");
                ddlPls_SelectedIndexChanged(null, null);
            }
        }

        private void lbPls_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (lbPls.SelectedIndex == -1) return;
            {
                // поиск amv
                AMV amv = null;
                for (int i = 0; i < Gl.DB.Count; i++)
                    if (Gl.DB[i].MD5Len == pl[ddlPls.SelectedIndex].Itm[lbPls.SelectedIndex].MD5Len) { amv = Gl.DB[i]; break; }

                if (amv == null)
                {
                    MessageBox.Show("Не найдено amv в списке");
                    ReDrawPl();
                    return;
                }
                OpenPl(pl[ddlPls.SelectedIndex], lbPls.SelectedIndex);
            }
        }

        private void menuPl_Opening(object sender, CancelEventArgs e)
        {
            if (lbPls.SelectedIndex == -1) e.Cancel = true;
        }

        private void mBtnDelPlItem_Click(object sender, EventArgs e)
        {
            pl[ddlPls.SelectedIndex].Itm.RemoveAt(lbPls.SelectedIndex);
            pl[ddlPls.SelectedIndex].Save();
            ReDrawPl();
        }

        private void mBtnFingInDB_Click(object sender, EventArgs e)
        {
            PlayListItem plsItm = pl[ddlPls.SelectedIndex].Itm[lbPls.SelectedIndex];
            foreach (AMV amv in AmvShowList)
            {
                if (amv.MD5Len == plsItm.MD5Len)
                {
                    lv.SelectedIndices.Clear();
                    lv.SelectedIndices.Add(AmvShowList.IndexOf(amv));
                    amv.itm.EnsureVisible();
                    //lv.EnsureVisible(ind);
                    lv.Focus();
                    return;
                }
            }

            // если в листе не найдено. Смотрим в базе (в листе может не быть из-за фильтров)
            if (Gl.DB.IndexOfMD5(plsItm.MD5Len) != -1)
            {
                MessageBox.Show("Запись в базе найдена, но она не отображена, так как установлен фильтр. Уберите фильтр и попробуйте снова");
            }
            else
            {
                MessageBox.Show("Такой записи в базе больше нет");
                lbPls.Itm[lbPls.SelectedIndex].brText = new SolidBrush(Color.Red);
                lbPls.Refresh();
            }
        }

        private void lbPls_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {
            if (e.KeyCode == Keys.Delete && lbPls.SelectedIndex != -1)
            {
                mBtnDelPlItem_Click(null, null);
            }
        }

        private void lbPls_SelectedItemChanged(object Sender)
        {
            lbPls.Focus();
        }

        #endregion *** плейлисты ************************************************

        #region *** прочие ФИИ ************************************************

        void LoadDB()
        {
            Gl.DB = new AMVCollection(Gl.fPathDb);

            // Смотрим, есть ли отличающиеся файлы. Только по длине
            dtNextCheckExist = DateTime.MinValue;
            dtNextFindNew = DateTime.MinValue;
            forCheck_IsFirstCheckNotEqual = true;

            ReFillDdlPl("");

            DBItem.LoadRec = Gl.LoadRec;
            Gl.LoadTagDB();
            Gl.SincTagDirs();
            ActTagDir = Gl.TagDB;

            RefillLvTags(false);
            ReFillAmv(true, false);
        }

        void OpenPl(PlayList pls, int startAmv)
        {
            if (!File.Exists(Gl.Sett.FPathPlayer)) { MessageBox.Show("Не найден проигрыватель. Зайдите в настройки и укажите путь к проигрывателю"); return; }

            // нахождение загружаемого списка, учитывая стартовое amv
            List<AMV> amvL = new List<AMV>();
            for (int pp = startAmv; pp < (pls.Itm.Count + startAmv); pp++)
            {
                int p = pp; if (pp >= pls.Itm.Count) p = pp - pls.Itm.Count;
                AMV amv = null;
                for (int i = 0; i < Gl.DB.Count; i++)
                    if (Gl.DB[i].MD5Len == pls.Itm[p].MD5Len) { amv = Gl.DB[i]; break; }
                if (amv != null)
                    if (File.Exists(Gl.Sett.DPathHomeDir + amv.FLocalPath))
                        amvL.Add(amv);
            }

            if (amvL.Count == 0)
            {
                MessageBox.Show("Внимание! Плейлист не может быть открыт, так как в нем не на найдено ни одного AMV из базы с верно указанным файлом");
                return;
            }

            // заполнение плейлиста
            StringBuilder mpcpl = new StringBuilder();
            mpcpl.AppendLine("MPCPLAYLIST");
            for (int i = 0; i < amvL.Count; i++)
            {
                string Autor = "";
                if (amvL[i].Atr.Count > 0)
                {
                    Autor = " (" + amvL[i].Atr[0];
                    if (amvL[i].Atr.Count > 1) Autor += " || ...";
                    Autor += ")";
                }

                mpcpl.AppendLine((i + 1).ToString() + ",type,0");
                mpcpl.AppendLine((i + 1).ToString() + ",label," + amvL[i].Name + Autor);
                mpcpl.AppendLine((i + 1).ToString() + ",filename," + amvL[i].FullPath);
                /*label, subtitle, video, audio, vinput, vchannel, ainput и country*/
            }

            if (amvL.Count != pls.Itm.Count)
                MessageBox.Show("Внимание! Некоторые AMV небыли добавлены в плейлист плеера, так как они не найдены в базе или для них указыаны неверные пути");

            File.WriteAllText(Application.StartupPath + "\\tmpPlayList.mpcpl", mpcpl.ToString(), Encoding.UTF8);
            Process.Start(Gl.Sett.FPathPlayer, "\"" + Application.StartupPath + "\\tmpPlayList.mpcpl" + "\"");
        }

        void UpdateHomeDir(bool OnlyNew, bool bCheckNotEqual)
        {
            tmrCheckNew.Stop();
            FormParseFromDir frmLoad = new FormParseFromDir();
            if (bCheckNotEqual) frmLoad.ShowDialogCheckNotEqual();
            else frmLoad.ShowDialog(OnlyNew);
            frmLoad.Dispose();

            Gl.DB.Save();

            FormLogMessage frmLogMessage = new FormLogMessage();
            frmLogMessage.ShowDialog("Информация по обновлению", Gl.fPathUpdateLog);
            frmLogMessage.Dispose();

            // синхронизация базы тегов
            Gl.SincTagDirs();
            RefillLvTags(false);
            ReFillAmv(true, false);
            tLblMessge.Visible = false;
            tmrCheckNew.Start();
        }

        bool bFltActive = false;
        void SetFltIco()
        {
            // кнопка сброса всех фильтров
            tBtnClearFlt.Enabled = IsFltActive(false);

            // отображение активности прочих фильтров
            if (IsFltActive(true))
            {
                if (!bFltActive)
                {
                    tBtnFlt.Image = Properties.Resources.flt_on;
                    bFltActive = true;
                }
            }
            else
            {
                if (bFltActive)
                {
                    tBtnFlt.Image = Properties.Resources.flt_off;
                    bFltActive = false;
                }
            }
        }

        bool IsFltActive(bool bOnlyOthrFlt)
        {
            if (!bOnlyOthrFlt)
            {
                if (tTxbGeneralFlt.Text != "") return true;
                if (ExTags.Count > 0) return true;
                if (FixTags.Count > 0) return true;
                foreach (Column clm in Gl.Sett.ClmL) if (clm.Flt != "") return true;  // фильтры по колонкам
                if (lvTags.SelectedItems.Count > 0) return true;    // фильтр по тегам
            }

            if (tBtnShowOnlyNotExist.Checked) return true;
            if (tBtnShowOnlyNotEqual.Checked) return true;
            if (tBtnShowOnlyAMVNews.Checked) return true;
            if (tBtnShowOnlyAkross.Checked) return true;
            if (tBtnShowOnlyCreaCon.Checked) return true;
            if (tBtnShowOnlyNotLink.Checked) return true;

            return false;
        }

        #endregion *** прочие ФИИ ************************************************

        #region *** поиск новых файлов и проверка существующих в фоне ************

        DateTime dtNextFindNew = DateTime.MinValue;
        DateTime dtNextCheckExist = DateTime.MinValue;
        enum CheckStat { None, FindNew, EndFindNew, CheckExis, EndCheckExis };
        CheckStat checkStat;

        int forCheck_CntNewAmv;
        int forCheck_CntNewNotExist = 0;
        int forCheck_CntNewNotEqual = 0;
        bool forCheck_IsFirstCheckNotEqual = true;
        object locker = new object();

        /// <summary> Проверяет, нет ли новых аниме (в фоне) </summary>
        void FindNewAmv()
        {
            int ret = 0;
            string dPathHomeDir = "";
            lock (Gl.Sett) dPathHomeDir = Gl.Sett.DPathHomeDir;
            if (Directory.Exists(dPathHomeDir))
            {
                String[] f = Directory.GetFiles(dPathHomeDir, "*", SearchOption.AllDirectories);
                for (int i = 0; i < f.Length; i++)
                {
                    if (!Gl.ExtIsMatch(new FileInfo(f[i]).Extension)) continue;
                    lock (Gl.DB) { if (Gl.DB.IndexOfFPath(f[i].Replace(dPathHomeDir, "")) != -1) continue; }
                    ret++;
                }
            }
            forCheck_CntNewAmv = ret;
            lock (locker) checkStat = CheckStat.EndFindNew;
        }

        void CheckExistAmv()
        {
            int cntNewNotExist = 0;
            int cntNewNotEqual = 0;

            int len = 0;
            lock (Gl.DB) len = Gl.DB.Count;

            string dPathHomeDir = "";
            lock (Gl.Sett) dPathHomeDir = Gl.Sett.DPathHomeDir;

            for (int i = 0; i < len; i++)
            {
                lock (Gl.DB) if (len != Gl.DB.Count) break;

                AMV amv = Gl.DB[i];
                string fPath = dPathHomeDir + amv.FLocalPath;

                // если файл более не существует по указанному пути
                if (!File.Exists(fPath))
                {
                    if (amv.Stat != AMV.Status.NotExist)
                    {
                        lock (amv) amv.Stat = AMV.Status.NotExist;
                        cntNewNotExist++;
                    }
                }
                else
                {
                    // если файл существует, но его длина не совпадает
                    if ((new FileInfo(fPath)).Length != amv.Len)
                    {
                        if (amv.Stat != AMV.Status.NotExist)
                        {
                            lock (amv) amv.Stat = AMV.Status.NotExist;
                            cntNewNotExist++;
                        }
                    }
                    else
                    {
                        // если файл вновь существует и совпадает по длине
                        if (amv.Stat == AMV.Status.NotExist)
                        {
                            lock (amv) amv.Stat = AMV.Status.NotEqual;
                            cntNewNotEqual++;
                        }
                    }
                }
            }

            lock (locker)
            {
                forCheck_CntNewNotExist = cntNewNotExist;
                forCheck_CntNewNotEqual = cntNewNotEqual;
                checkStat = CheckStat.EndCheckExis;
            }

        }

        string MessNewFiles = "";
        string MessExistFiles = "";

        private void tmrCheckNew_Tick(object sender, EventArgs e)
        {
            tmrCheckNew.Stop();

            switch (checkStat)
            {
                case CheckStat.None: // активных проверок нет
                    {
                        DateTime dt = DateTime.Now;
                        if (dtNextFindNew <= dt)
                        {
                            dtNextFindNew = dt.AddSeconds(Gl.Sett.PeriodFindNew);
                            checkStat = CheckStat.FindNew;
                            forCheck_CntNewAmv = 0;
                            lblBackProcess.Text = "Поиск новых файлов...";
                            lblBackProcess.Visible = true;
                            System.Threading.Thread th = new System.Threading.Thread(new System.Threading.ThreadStart(FindNewAmv));
                            th.Start();
                        }
                        else if (dtNextCheckExist <= dt)
                        {
                            dtNextCheckExist = dt.AddSeconds(Gl.Sett.PeriodCheckExist);
                            checkStat = CheckStat.CheckExis;
                            forCheck_CntNewNotExist = 0;
                            forCheck_CntNewNotEqual = 0;
                            lblBackProcess.Text = "Проверка существующих файлов...";
                            lblBackProcess.Visible = true;
                            System.Threading.Thread th = new System.Threading.Thread(new System.Threading.ThreadStart(CheckExistAmv));
                            th.Start();
                        }


                        break;
                    }

                case CheckStat.FindNew: // идет поиск новых файлов
                    {
                        break;
                    }

                case CheckStat.EndFindNew: // закончен поиск новых файлов
                    {
                        checkStat = CheckStat.None;

                        if (forCheck_CntNewAmv > 0) MessNewFiles = "[" + DateTime.Now.ToString("HH:mm") + "] Найдены новые AMV (" + forCheck_CntNewAmv.ToString() + " шт.)";
                        else MessNewFiles = "";
                        RefillMessageLabel(true);
                        lblBackProcess.Visible = false;
                        break;
                    }

                case CheckStat.CheckExis: // идет проверка существующих файлов
                    {
                        break;
                    }

                case CheckStat.EndCheckExis: // закончена проверка существующих файлов
                    {
                        checkStat = CheckStat.None;

                        if (forCheck_CntNewNotExist > 0 || forCheck_CntNewNotEqual > 0)
                        {
                            // если это первая проверка после открытия, выводим сообщение
                            if (forCheck_IsFirstCheckNotEqual)
                            {
                                Gl.DB.Save();
                                StringBuilder sb = new StringBuilder();
                                sb.AppendLine("Внимание!\r\nC последнего открытия некоторые файлы изменились.\r\n");
                                if (forCheck_CntNewNotExist > 0) sb.AppendLine("\r\nAMV, файлы которых более не существуют: " + forCheck_CntNewNotExist.ToString() + " шт.");
                                if (forCheck_CntNewNotEqual > 0) sb.AppendLine("\r\nAMV, файлы которых вновь найдены, но требуют детальной проверки: " + forCheck_CntNewNotEqual.ToString() + " шт.");

                                MessageBox.Show(sb.ToString());
                            }

                            // пересохраняем, поскольку статусы изменились
                            Gl.DB.Save();
                            UpdateIcoAmvList();
                            lv.Refresh();

                            MessExistFiles = "[" + DateTime.Now.ToString("HH:mm") + "] Изменились файлы:";
                            if (forCheck_CntNewNotExist > 0) MessExistFiles += " более не существует " + forCheck_CntNewNotExist.ToString() + " шт.";
                            if (forCheck_CntNewNotEqual > 0) MessExistFiles += " вновь найдены и требуют проверки " + forCheck_CntNewNotEqual.ToString() + " шт.";
                            tLblMessge.Visible = true;
                        }

                        forCheck_IsFirstCheckNotEqual = false; // говорим, что первая проверка прошла.
                        RefillMessageLabel(false);
                        lblBackProcess.Visible = false;

                        break;
                    }
            }

            tmrCheckNew.Start();
        }

        /// <summary>Перезаполнить информационное сообщение. </summary>
        /// <param name="MessNewPrior">true - приоритет у сообщения о новых файлах, false - приоритет у сообщения о сущестующих</param>
        void RefillMessageLabel(bool MessNewPrior)
        {
            if (MessNewFiles == "" && MessExistFiles == "") { tLblMessge.Visible = false; return; }

            if (MessNewPrior)
            {
                tLblMessge.Text = MessNewFiles != "" ? MessNewFiles : MessExistFiles;
            }
            else
            {
                tLblMessge.Text = MessExistFiles != "" ? MessExistFiles : MessNewFiles;
            }
            tLblMessge.Visible = true;
        }

        #endregion *** поиск новых файлов и проверка существующих в фоне ************

        private void tTxbGeneralFlt_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter) tBtnFlt.HideDropDown();
        }

        #region *** Теги *******************************************

        TagDIR ActTagDir;
        List<DBItem> CutElements = new List<DBItem>();

        /// <summary>исключенные теги. Запись, где есть хотя бы 1 исключенный тег не показывается</summary>
        List<string> ExTags = new List<string>();
        /// <summary>закрепленные теги. Запись, где нет хотя бы одного закрепленного тега не показывается</summary>
        List<string> FixTags = new List<string>();
        /// <summary>список тегов, по которым выберется хотя бы 1 запись. Список строится динамически при закреплении тегов. И остается пуст, если закрепленных тегов нет</summary>
        List<string> EmptyTags = new List<string>();

        Color clrDisabledItem = Color.FromArgb(197, 124, 124);

        /// <summary> Перезаполнение листа тегов для фильтров </summary>
        void RefillLvTags(bool SaveSelectedIfExist)
        {
            List<DBItem> selItems = new List<DBItem>();
            if (SaveSelectedIfExist && lvTags.SelectedItems.Count > 0)
                foreach (ListViewItem itm in lvTags.SelectedItems)
                    selItems.Add((DBItem)itm.Tag);

            lvTags.Items.Clear();

            List<DBItem> tagDirL = ActTagDir.GetRecords(new string[1] { "" });
            tagDirL.Sort();
            for (int i = 0; i < tagDirL.Count; i++)
            {
                ListViewItem itm = new ListViewItem(tagDirL[i].Name);
                itm.Tag = tagDirL[i];
                lvTags.Items.Add(itm);
            }

            List<DBItem> tagL = ActTagDir.GetRecords(new string[1] { "TAG" });
            tagL.Sort();
            for (int i = 0; i < tagL.Count; i++)
            {
                ListViewItem itm = new ListViewItem(tagL[i].Name);
                itm.Tag = tagL[i];
                lvTags.Items.Add(itm);
            }

            // возврат селекта
            if (selItems.Count > 0)
            {
                for (int i = 0; i < lvTags.Items.Count; i++)
                {
                    foreach (DBItem selItem in selItems)
                    {
                        if (((DBItem)lvTags.Items[i].Tag).FullPath == selItem.FullPath)
                        {
                            lvTags.SelectedIndices.Add(i);
                            break;
                        }
                    }
                }
            }

            lblTagPath.Text = ActTagDir.FPath + "\\*.*";

            SetFltIco();

            //ResetIcoAndColorTags();
        }

        void ResetIcoAndColorTags()
        {
            foreach (ListViewItem itm in lvTags.Items)
            {
                DBItem dbItem = (DBItem)itm.Tag;
                // каталог
                if (dbItem.IsDirectory)
                {
                    itm.ImageIndex = 0;
                    itm.ForeColor = Color.Black;

                    List<DBItem> tagsInDir = dbItem.GetAllRecords(new string[1] { "TAG" });
                    if (tagsInDir.Count > 0)
                    {
                        // пустые и исключенные теги в каталоге
                        if (ExTags.Count > 0 || EmptyTags.Count > 0)
                        {
                            bool bExOrEmptyAll = true;
                            bool bExSome = false;
                            foreach (DBItem tagInDir in tagsInDir)
                            {
                                if (!ExTags.Contains(tagInDir.Name) && !EmptyTags.Contains(tagInDir.Name)) bExOrEmptyAll = false;
                                if (ExTags.Contains(tagInDir.Name)) bExSome = true;
                            }
                            if (bExOrEmptyAll)
                            {
                                itm.ImageIndex = bExSome ? 5 : 4;
                                itm.ForeColor = Color.Gray;
                            }
                            else if (bExSome) itm.ImageIndex = 1;

                        }

                        // закрепленные теги в каталоге
                        if (FixTags.Count > 0)
                        {
                            // закрепленные теги
                            bool bFIXAll = true;
                            bool bFIXSome = false;
                            foreach (DBItem tagInDir in tagsInDir)
                            {
                                if (!FixTags.Contains(tagInDir.Name)) { bFIXAll = false; }
                                else bFIXSome = true;
                                if (bFIXAll == false && bFIXSome) break;
                            }
                            if (bFIXSome) itm.ImageIndex = 2;
                            if (bFIXAll) { itm.ForeColor = Color.Blue; }
                        }
                    }
                }
                // тег
                else
                {
                    itm.ImageIndex = 6;
                    itm.ForeColor = Color.Black;

                    //если тег в исключенных
                    if (ExTags.Contains(dbItem.Name))
                    {
                        itm.ImageIndex = 7;
                        itm.ForeColor = clrDisabledItem;
                    }

                    // закрепленные теги
                    if (FixTags.Count > 0)
                    {
                        //если тег в закрепленных
                        if (FixTags.Contains(dbItem.Name))
                        {
                            itm.ImageIndex = 8;
                            itm.ForeColor = Color.Blue;
                        }
                    }

                    if (EmptyTags.Count > 0 && itm.ImageIndex == 6)
                    {
                        // пустые теги
                        if (itm.ImageIndex == 6)
                        {
                            if (EmptyTags.Contains(dbItem.Name))
                            {
                                itm.ImageIndex = 9;
                                itm.ForeColor = Color.Gray;
                            }
                        }
                    }

                }

                // вырезанныые элементы
                foreach (DBItem cutEl in CutElements) if (cutEl.FullPath == dbItem.FullPath) itm.ForeColor = Color.LightGray;
            }
        }

        /// <summary> редактирование имени тега (отредактируются имя тега для всех записей, где он есть)</summary>
        private void lvTags_AfterLabelEdit(object sender, LabelEditEventArgs e)
        {
            if (e.Label == null) return;

            string oldName = lvTags.SelectedItems[0].Text;
            string newName = e.Label;

            // каталог
            if (((DBItem)lvTags.SelectedItems[0].Tag).IsDirectory)
            {
                // проверка на дубликат
                if (ActTagDir.IndexOfRecord(newName, "") != -1)
                {
                    MessageBox.Show("Каталог с таким именем уже есть");
                    e.CancelEdit = true;
                    return;
                }
                ((DBItem)lvTags.SelectedItems[0].Tag).Name = newName;
                Gl.SaveTagDB();
            }
            // таг
            else
            {
                TAG tag = (TAG)lvTags.SelectedItems[0].Tag;

                // смотрим, не дублируется ли тег с каким-то другим. Если да, Выдаем предупреждение
                List<string> tagL = Gl.DB.GetAllTags();
                int indDupl = tagL.IndexOf(newName);
                if (indDupl != -1)
                {
                    if (MessageBox.Show("Внимание! Есть другой тег с таким же именем. Объединить теги", "Переименование", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == System.Windows.Forms.DialogResult.No)
                    {
                        e.CancelEdit = true;
                        return;
                    }
                }

                // бекап перед переименованием
                Backup.SaveBackup(Action.EditTags, oldName + " -- " + newName);

                // переименование в записях
                for (int i = 0; i < Gl.DB.Count; i++)
                {
                    int ind = Gl.DB[i].Tags.IndexOf(oldName);
                    // если у записи есть таг, который переименовывается 
                    if (ind != -1)
                    {
                        // если среди остальных тагов нет тага с именем после перименования, то переименовываем
                        if (Gl.DB[i].Tags.IndexOf(newName) == -1)
                        {
                            Gl.DB[i].Tags[ind] = newName;
                        }
                        // иначе (если тег с таким именем уже есть) просто удаляем
                        else
                        {
                            Gl.DB[i].Tags.RemoveAt(ind);
                        }
                    }
                }

                // если есть дубликат, просто удаляем его из тег-базы и из видимого списка
                if (indDupl != -1)
                {
                    // удаление из тег-базы  тега-дубликата
                    List<DBItem> tagDBL = Gl.TagDB.GetAllRecords(new string[1] { "TAG" });
                    for (int i = 0; i < tagDBL.Count; i++)
                        if (tagDBL[i].Name == newName)
                        {
                            // удаление из базы тегов
                            tagDBL[i].Parent.Items.Remove(tagDBL[i]);
                            break;
                        }

                    // удаление из видимого списка
                    lvTags.Items.RemoveAt(lvTags.SelectedIndices[0]);
                    e.CancelEdit = true;
                }

                // переименование в базе
                tag.Name = newName;
                Gl.SaveTagDB();
                ReFillAmv(true, true);
                Gl.DB.Save();
            }
        }

        private void menuTags_Opening(object sender, CancelEventArgs e)
        {
            mBtnTagDelete.Enabled = lvTags.SelectedItems.Count > 0;

            mBtnTagsCut.Enabled = lvTags.SelectedItems.Count > 0;
            mBtnTagsPaste.Enabled = CutElements.Count > 0 && (lvTags.SelectedItems.Count == 0 || ((DBItem)lvTags.SelectedItems[0].Tag).IsDirectory);

            mBtnTagsCreateDir.Enabled = lvTags.SelectedItems.Count == 0;

            #region *** Исключенные и закрепленные теги ***
            List<TAG> selTags = GetAllSelectedTags();
            bool bAdd_EX = false;
            bool bDel_EX = false;
            if (lvTags.SelectedItems.Count > 0)
            {
                foreach (TAG selTag in selTags)
                {
                    if (!ExTags.Contains(selTag.Name)) bAdd_EX = true;
                    if (ExTags.Contains(selTag.Name)) bDel_EX = true;
                }
                mBtnAddInExTagList.Enabled = bAdd_EX;
                mBtnDeleteFromExTagList.Enabled = bDel_EX;

                // закрепленные теги
                TAG firstSelTag = null;
                if (!((DBItem)lvTags.SelectedItems[0].Tag).IsDirectory) firstSelTag = (TAG)lvTags.SelectedItems[0].Tag;
                mBtnFixTag.Enabled = firstSelTag != null && !EmptyTags.Contains(firstSelTag.Name) && !FixTags.Contains(firstSelTag.Name);
                mBtnDelFixTag.Enabled = firstSelTag != null && FixTags.Contains(firstSelTag.Name);
            }
            else
            {
                mBtnAddInExTagList.Enabled = false;
                mBtnDeleteFromExTagList.Enabled = false;
                mBtnFixTag.Enabled = false;
                mBtnDelFixTag.Enabled = false;
            }

            #endregion *** Исключенные и закрепленные теги ***

        }

        private void mBtnTagDelete_Click(object sender, EventArgs e)
        {
            DBItem itemForDel = (DBItem)lvTags.SelectedItems[0].Tag;

            bool bDel = false;

            if (itemForDel.IsDirectory)
            {
                if (MessageBox.Show("Действительно удалить каталог?Будут удалены все теги в каталоге", "Удаление каталога", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    Backup.SaveBackup(Action.DelTagInAllRecs, itemForDel.Name); // бэкап
                    DeleteAllTagsInDirectory((TagDIR)itemForDel);
                    itemForDel.Parent.Items.Remove(itemForDel);
                    bDel = true;
                }
            }
            else
            {
                if (MessageBox.Show("Действительно удалить тег? Тег будет удален из всех записей", "Удаление тега", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    Backup.SaveBackup(Action.DelTagInAllRecs, itemForDel.Name); // бэкап
                    DeleteTag((TAG)itemForDel);
                    bDel = true;
                }
            }

            if (bDel)
            {
                RefillLvTags(false);
                ReFillAmv(true, true);

                Gl.SaveTagDB();
                Gl.DB.Save();
            }
        }

        void DeleteAllTagsInDirectory(TagDIR dir)
        {
            for (int i = 0; i < dir.Items.Count; i++)
            {
                if (dir.Items[i].IsDirectory)
                {
                    DeleteAllTagsInDirectory((TagDIR)dir.Items[i]);
                }
                else
                {
                    DeleteTag((TAG)dir.Items[i]);
                    i--;
                }
            }
        }

        void DeleteTag(TAG tag)
        {
            // удаление тега из всех записей в базе
            for (int i = 0; i < Gl.DB.Count; i++)
            {
                int ind = Gl.DB[i].Tags.IndexOf(tag.Name);
                if (ind != -1) Gl.DB[i].Tags.RemoveAt(ind);
            }

            // удаление из базы тегов
            tag.Parent.Items.Remove(tag);
        }

        private void lvTags_SelectedIndexChanged(object sender, EventArgs e)
        {
            //
        }

        private void lvTags_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (lvTags.SelectedIndices.Count > 0)
            {
                // если каталог
                if (((DBItem)lvTags.SelectedItems[0].Tag).IsDirectory)
                {
                    ActTagDir = (TagDIR)lvTags.SelectedItems[0].Tag;
                    RefillLvTags(false);
                    ResetIcoAndColorTags();
                    tBtnTagsUp.Enabled = true;
                }
                // если тег, закрепляем или снимаем закрепление
                else
                {
                    if (FixTags.Contains(lvTags.SelectedItems[0].Text)) mBtnDelFixTag_Click(null, null);
                    else if (!EmptyTags.Contains(lvTags.SelectedItems[0].Text)) mBtnFixTag_Click(null, null);
                }
            }
        }

        List<AMV> GetAllAmvBySelectedTags()
        {
            List<AMV> ret = new List<AMV>();

            foreach (ListViewItem itm in lvTags.SelectedItems)
            {
                // составляем список выбранных тегов
                List<string> fltTagL = new List<string>();
                if (((DBItem)itm.Tag).IsDirectory)
                {
                    List<DBItem> dbTagList = ((TagDIR)itm.Tag).GetAllRecords(new string[1] { "TAG" });
                    foreach (DBItem dbTag in dbTagList) fltTagL.Add(dbTag.Name);
                }
                else fltTagL.Add(itm.Text);

                for (int i = 0; i < Gl.DB.Count; i++)
                {
                    bool bFind = false;

                    // смотрим соответствие
                    foreach (string tag in Gl.DB[i].Tags)
                    {
                        foreach (string fltTag in fltTagL)
                        {
                            if (fltTag == tag) { bFind = true; break; }
                        }
                        if (bFind) break;
                    }

                    if (bFind) ret.Add(Gl.DB[i]);
                }
            }
            ret.Sort();

            return ret;
        }

        private void lvTags_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                if (lvTags.SelectedItems.Count > 0 && ((DBItem)lvTags.SelectedItems[0].Tag).IsDirectory)
                {
                    lvTags_MouseDoubleClick(null, null);
                }
            }
            if (e.KeyCode == Keys.Back)
            {
                if (tBtnTagsUp.Enabled) tBtnTagsUp_Click(null, null);
            }
            if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down || e.KeyCode == Keys.Left || e.KeyCode == Keys.Right)
            {
                ReFillAmv();
                SetFltIco();
            }
        }

        private void lvTags_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Middle)
            {
                // исключение тега по клику колесиком
                ListViewItem itm = lvTags.GetItemAt(e.X, e.Y);
                if (itm != null)
                {
                    // если тег уже в исключенных, убираем его оттуда
                    if (ExTags.Contains(itm.Text)) DeleteFromExTagList(new List<TAG>() { (TAG)itm.Tag });
                    // иначе исключаем
                    else AddInExTagList(new List<TAG>() { (TAG)itm.Tag });
                }
            }

            ReFillAmv();
            SetFltIco();
        }

        private void tBtnTagsUp_Click(object sender, EventArgs e)
        {
            ActTagDir = (TagDIR)ActTagDir.Parent;
            if (ActTagDir.Parent == null) tBtnTagsUp.Enabled = false;

            RefillLvTags(false);
            ReFillAmv();
        }

        #region *** меню тегов для добавления ********************************

        private void mBtnAddTagInRec_DropDownOpening(object sender, EventArgs e)
        {
            mBtnAddTagInRec.DropDownItems.Clear();

            // выбираем теги, которые добавлять не надо (которые есть во всех выбранных записях)
            // пока не надо. Чтобы в выпадающем списке была та же картина, что и в тегах
            //List<string> NotAddTags = new List<string>();

            ToolStripMenuItem itm;

            // последние добавленные и выбранные теги
            foreach (string tag in LastTags)
            {
                itm = GetTagMenuItem(tag, false, mBtnTagForAdd_Click);
                itm.ForeColor = Color.Blue;
                mBtnAddTagInRec.DropDownItems.Add(itm);
            }
            // если последние добавленные теги есть, ставим сепаратор
            if (mBtnAddTagInRec.DropDownItems.Count > 0) mBtnAddTagInRec.DropDownItems.Add(new ToolStripSeparator());

            // все теги (по каталогам)
            AddMBtnTags(mBtnAddTagInRec, Gl.TagDB);

            // если ничего не добавлено, добавляем пустую кнопку (нет не добавленных тегов)
            if (mBtnAddTagInRec.DropDownItems.Count == 0)
            {
                mBtnAddTagInRec.DropDownItems.Add("нет не добавленных тегов");
                mBtnAddTagInRec.DropDownItems[0].Enabled = false;
            }
        }

        void AddMBtnTags(ToolStripMenuItem ParentItm, TagDIR ParentDir)
        {
            List<DBItem> DirL = ParentDir.GetDirectories(false);
            foreach (DBItem dir in DirL)
            {
                ToolStripMenuItem itm = GetTagMenuItem(dir.Name, true, mBtnTagForAdd_Click);
                AddMBtnTags(itm, (TagDIR)dir);
                ParentItm.DropDownItems.Add(itm);
            }

            List<DBItem> TagL = ParentDir.GetRecords(new string[1] { "TAG" });
            foreach (DBItem tag in TagL)
            {
                ToolStripMenuItem itm = GetTagMenuItem(tag.Name, false, mBtnTagForAdd_Click);
                ParentItm.DropDownItems.Add(itm);
            }
        }

        // добавление тега во все выделенные записи
        private void mBtnTagForAdd_Click(object sender, EventArgs e)
        {
            string TagForAdd = ((ToolStripMenuItem)sender).Text;
            AddLastTag(TagForAdd);
            Backup.SaveBackup(Action.AddTag);
            foreach (int ind in lv.SelectedIndices)
            {
                if (!AmvShowList[ind].Tags.Contains(TagForAdd))
                {
                    AmvShowList[ind].Tags.Add(TagForAdd);
                    AmvShowList[ind].UpdateItm(lv.Columns);
                }
            }
            ReFillAmv(); // перезаполняем список, поскольку новый тег мог оказаться в исключенных
            Gl.DB.Save();
        }

        /// <summary>Добавление тега в список последних добавленых тегов</summary>
        void AddLastTag(string TagForAdd)
        {
            int ind = LastTags.IndexOf(TagForAdd);
            if (ind != -1) LastTags.RemoveAt(ind);
            LastTags.Insert(0, TagForAdd);
            while (LastTags.Count > Gl.Sett.LastTagsSize) LastTags.RemoveAt(LastTags.Count - 1);
        }

        #endregion *** меню тегов для добавления ********************************

        ToolStripMenuItem GetTagMenuItem(string tagName, bool bDir, EventHandler Tag_Click)
        {
            ToolStripMenuItem itm = new ToolStripMenuItem(tagName, bDir ? imListTags.Images[0] : imListTags.Images[6]);
            if (!bDir) itm.Click += new EventHandler(Tag_Click);
            return itm;
        }

        #region *** меню тегов для удаления ********************************

        private void mBtnDelTagFromRec_DropDownOpening(object sender, EventArgs e)
        {
            mBtnDelTagFromRec.DropDownItems.Clear();

            // выбираем все теги, которые можно удалить
            List<string> TagsForDel = new List<string>();
            foreach (int ind in lv.SelectedIndices)
            {
                foreach (string tag in AmvShowList[ind].Tags)
                {
                    if (!TagsForDel.Contains(tag))
                        TagsForDel.Add(tag);
                }
            }
            TagsForDel.Sort();

            // выбираем теги, которые присутствуют во всех выделенных записях
            List<string> TagsForDelInAll = new List<string>(TagsForDel);
            foreach (int ind in lv.SelectedIndices)
            {
                for (int i = 0; i < TagsForDelInAll.Count; i++)
                {
                    if (!AmvShowList[ind].Tags.Contains(TagsForDelInAll[i]))
                    {
                        TagsForDelInAll.RemoveAt(i);
                        i--;
                    }
                }

            }

            foreach (string tag in TagsForDel)
            {
                ToolStripMenuItem itm = GetTagMenuItem(tag, false, mBtnTagForDel_Click);
                if (!TagsForDelInAll.Contains(tag))
                {
                    //itm.ForeColor = Color.FromArgb(70, 70, 70);
                    itm.Image = imListTags.Images[9];
                }
                mBtnDelTagFromRec.DropDownItems.Add(itm);
            }

            // если ничего не добавлено, добавляем пустую кнопку (нет не добавленных тегов)
            if (mBtnDelTagFromRec.DropDownItems.Count == 0)
            {
                mBtnDelTagFromRec.DropDownItems.Add("нет тегов для удаления");
                mBtnDelTagFromRec.DropDownItems[0].Enabled = false;
            }
        }

        // удаление тега из всех выделенных записи
        private void mBtnTagForDel_Click(object sender, EventArgs e)
        {
            string tagForDel = ((ToolStripMenuItem)sender).Text;
            Backup.SaveBackup(Action.DeleteTag);
            foreach (int ind in lv.SelectedIndices)
            {
                if (AmvShowList[ind].Tags.Contains(tagForDel))
                {
                    AmvShowList[ind].Tags.Remove(tagForDel);
                    AmvShowList[ind].UpdateItm(lv.Columns);
                }
            }
            ReFillAmv(); // перезаполняем список, поскольку по этому тегу могла быть фильтрация
            Gl.DB.Save();
        }

        #endregion *** меню тегов для удаления ********************************

        #region *** выпадающее меню тегов **********************

        /// <summary> Добавить каталог</summary>
        private void mBtnTagsCreateDir_Click(object sender, EventArgs e)
        {
            ESpace.FormEditValue frm = new ESpace.FormEditValue();
            if (frm.ShowDialog("", true))
            {
                string retVal = ((string)frm.Value).Trim();
                // проверка на дубликат
                if (ActTagDir.IndexOfRecord(retVal, "") != -1)
                {
                    MessageBox.Show("Каталог с таким именем уже существует");
                    return;
                }

                ActTagDir.Items.Add(new TagDIR(retVal, ActTagDir));
                Gl.SaveTagDB();

                RefillLvTags(false);
                ResetIcoAndColorTags();
            }

        }

        private void mBtnTagsCut_Click(object sender, EventArgs e)
        {
            CutElements.Clear();
            ResetIcoAndColorTags();
            foreach (ListViewItem selItm in lvTags.SelectedItems)
            {
                CutElements.Add((DBItem)selItm.Tag);
                selItm.ForeColor = Color.LightGray;
            }
            lvTags.SelectedItems.Clear();
        }

        private void mBtnTagsPaste_Click(object sender, EventArgs e)
        {
            DBItem DestDir = ActTagDir;
            if (lvTags.SelectedItems.Count > 0)
            {
                DestDir = (TagDIR)lvTags.SelectedItems[0].Tag;
            }

            // проверки
            foreach (DBItem cutEl in CutElements)
            {
                // проверка на вставку элемента в тот же каталог
                if (cutEl.Parent.FullPath == DestDir.FullPath)
                {
                    CutElements.Clear();
                    //RefillLvTags(true);
                    ResetIcoAndColorTags();
                    return;
                }

                // проверка на вставку каталога в самого себя или в дочерний каталог этого каталога
                if (cutEl.IsDirectory)
                {
                    if (DestDir.FullPath == cutEl.FullPath)
                    {
                        MessageBox.Show("Нельзя вставить каталог в сомого себя");
                        return;
                    }

                    List<DBItem> subDir = cutEl.GetAllRecords(new string[1] { "" });
                    bool bSubItem = false;
                    for (int i = 0; i < subDir.Count; i++) if (subDir[i].FullPath == DestDir.FullPath) { bSubItem = true; break; }
                    if (bSubItem)
                    {
                        MessageBox.Show("Нельзя вставить каталог в свой же подкаталог");
                        return;
                    }

                    // проверка на дубликат
                    if (DestDir.IndexOfRecord(cutEl.Name, "") != -1)
                    {
                        MessageBox.Show("В этом каталоге уже есть подкаталог с таким же именем");
                        return;
                    }
                }
            }

            // вставка
            foreach (DBItem cutEl in CutElements)
            {
                cutEl.Parent.Items.Remove(cutEl);
                cutEl.Parent = DestDir;
                DestDir.Items.Add(cutEl);
            }
            Gl.SaveTagDB();
            CutElements.Clear();
            RefillLvTags(false);
            ResetIcoAndColorTags();
        }

        private void mBtnAddInExTagList_Click(object sender, EventArgs e)
        {
            List<TAG> selTagL = GetAllSelectedTags();
            AddInExTagList(selTagL);

            lvTags.SelectedItems.Clear();
            ReFillAmv();
        }

        private void mBtnDeleteFromExTagList_Click(object sender, EventArgs e)
        {
            List<TAG> selTagL = GetAllSelectedTags();
            DeleteFromExTagList(selTagL);
            ReFillAmv();
        }

        void AddInExTagList(List<TAG> selTagL)
        {
            foreach (TAG tag in selTagL)
            {
                if (!ExTags.Contains(tag.Name)) ExTags.Add(tag.Name);
                if (FixTags.Contains(tag.Name)) FixTags.Remove(tag.Name);
            }
        }

        void DeleteFromExTagList(List<TAG> selTagL)
        {
            foreach (TAG tag in selTagL)
                if (ExTags.Contains(tag.Name))
                    ExTags.Remove(tag.Name);
        }

        private void mBtnFixTag_Click(object sender, EventArgs e)
        {
            List<TAG> selTagL = GetAllSelectedTags();
            foreach (TAG tag in selTagL)
            {
                if (!FixTags.Contains(tag.Name)) FixTags.Add(tag.Name);
                if (ExTags.Contains(tag.Name)) ExTags.Remove(tag.Name);
            }

            ReFillAmv();
        }

        private void mBtnDelFixTag_Click(object sender, EventArgs e)
        {
            List<TAG> selTagL = GetAllSelectedTags();
            foreach (TAG tag in selTagL) if (FixTags.Contains(tag.Name)) FixTags.Remove(tag.Name);

            ReFillAmv();
        }

        #endregion *** выпадающее меню тегов **********************

        List<TAG> GetAllSelectedTags()
        {
            List<TAG> ret = new List<TAG>();
            foreach (ListViewItem selItm in lvTags.SelectedItems)
            {
                DBItem dbItm = (DBItem)selItm.Tag;
                if (dbItm.IsDirectory)
                {
                    TagDIR dir = (TagDIR)dbItm;
                    List<DBItem> itms = dir.GetAllRecords(new string[1] { "TAG" });
                    foreach (DBItem itm in itms) ret.Add((TAG)itm);
                }
                else
                {
                    ret.Add((TAG)dbItm);
                }
            }
            return ret;
        }

        #endregion *** Теги *******************************************

        /// <summary> заполнить теги по именам каталогов </summary>
        private void tBtnFillTagsFromDir_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Действительно заполнить теги по именам каталогов?\r\n(Будут заполнены теги только если их нет)", "Заполнение тегов", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                // бэкап
                Backup.SaveBackup(Action.EditTags);

                for (int i = 0; i < Gl.DB.Count; i++)
                {
                    int ind = Gl.DB[i].FLocalPath.LastIndexOf('\\');
                    if (ind > 0)
                    {
                        string tag = Gl.DB[i].FLocalPath.Substring(0, ind);
                        if (!Gl.DB[i].Tags.Contains(tag)) Gl.DB[i].Tags.Add(tag);
                    }
                }
                Gl.DB.Save();
                Gl.SincTagDirs();
                RefillLvTags(false);
                ReFillAmv(true, true);
            }
        }

        private void tBtnHotHelp_Click(object sender, EventArgs e)
        {
            try
            {
                Process.Start(Application.StartupPath + "\\HotHelp.txt");
            }
            catch { MessageBox.Show("Не найден файл помощи"); }
        }

        private void lv_SelectedIndexChanged(object sender, EventArgs e)
        {
            ReFillInfo();
        }

        void ReFillInfo()
        {
            if (SelAmv == null || lv.SelectedIndices.Count > 1) { txbInfo.Text = ""; return; }

            StringBuilder sb = new StringBuilder();

            // авторы
            sb.Append(SelAmv.Atr.Count > 1 ? "АВТОРЫ: " : "АВТОР: ");
            if (SelAmv.Atr.Count > 0)
            {
                sb.Append(SelAmv.Atr[0]);
                for (int i = 1; i < SelAmv.Atr.Count; i++) sb.Append(" || " + SelAmv.Atr[i]);
            }
            sb.Append("\r\n");

            // музыка
            sb.Append("МУЗЫКА: ");
            if (SelAmv.Msc.Count > 0)
            {
                sb.Append(SelAmv.Msc[0].Author + " - " + SelAmv.Msc[0].Name);
                for (int i = 1; i < SelAmv.Msc.Count; i++) sb.Append(" || " + SelAmv.Msc[i].Author + " - " + SelAmv.Msc[i].Name);
            }
            sb.Append("\r\n");

            // награды
            sb.Append("НАГРАДЫ: ");
            if (SelAmv.Awd.Count > 0)
            {
                if (SelAmv.Awd.Count == 1)
                {
                    sb.Append(SelAmv.Awd[0]);
                }
                else
                {
                    sb.Append("\r\n\t" + SelAmv.Awd[0]);
                    for (int i = 1; i < SelAmv.Awd.Count; i++) sb.Append("\r\n\t" + SelAmv.Awd[i]);
                }
            }
            sb.Append("\r\n");

            // рейтинг
            Dictionary<SITE, AMVSite> sites = SelAmv.GetSitesWithRating();
            if (sites.Count == 0) sb.Append("ОЦЕНКА: нет\r\n");
            else
            {
                sb.Append("ОЦЕНКА: " + SelAmv.MiddleRating.ToString() + "\r\n");
                if (sites.Count > 1)
                    foreach (KeyValuePair<SITE, AMVSite> site in sites)
                        sb.Append("\t- " + site.Key.ToString() + ": " + site.Value.Rating + "\r\n");
            }

            sb.Append("\r\n");

            // коментарий
            sb.Append("*** КОМЕНТАРИЙ **************************************************\r\n");
            sb.Append(SelAmv.Comment);
            sb.Append("\r\n*************************************************************************\r\n");

            // список аниме
            if (SelAmv.Anm.Count > 0)
            {
                sb.Append("АНИМЕ:" + SelAmv.Anm[0]);
                for (int i = 1; i < SelAmv.Anm.Count; i++) sb.Append(" || " + SelAmv.Anm[i]);
            }

            sb.Append("\r\n*************************************************************************\r\n");

            // теги
            AppendInfo(SelAmv.Tags, "ТЕГИ", sb);

            // ключевые слова
            AppendInfo(SelAmv.KeyWords, "КЛЮЧЕВЫЕ СЛОВА", sb);

            txbInfo.Text = sb.ToString();
        }

        void AppendInfo(List<string> sl, string Title, StringBuilder sb)
        {
            sb.Append(Title + ": ");
            if (sl.Count == 0) return;

            sb.Append(sl[0]);
            for (int i = 1; i < sl.Count; i++) sb.Append(" || " + sl[i]);

            sb.Append("\r\n*************************************************************************\r\n");
        }

        private void tBtnAmvInfo_Click(object sender, EventArgs e)
        {
            if (frmAmvInfo == null) frmAmvInfo = new FormAmvInfo();
            frmAmvInfo.Show();
            frmAmvInfo.WindowState = FormWindowState.Normal;
        }

        private void tBtnUpdateRatings_Click(object sender, EventArgs e)
        {
            Backup.SaveBackup(Action.UpdateRatings);
            FormUpdateRating frm = new FormUpdateRating();
            string fPathLog;
            frm.ShowDialog(out fPathLog);
            frm.Dispose();

            ReFillAmv(true, true);
            Gl.DB.Save();

            FormLogMessage frmLogMessage = new FormLogMessage();
            frmLogMessage.ShowDialog("Информация по обновлению рейтингов", fPathLog);
            frmLogMessage.Dispose();
        }

        private void tBtnLinkToAMVNews_Click(object sender, EventArgs e)
        {
            FormLinkToSite frm = new FormLinkToSite();
            frm.ShowDialog();
            if (frm.bOK)
            {
                Gl.SincTagDirs();
                RefillLvTags(true);
                ReFillAmv(true, true);

                FormLogMessage frmLogMessage = new FormLogMessage();
                frmLogMessage.ShowDialog("Информация по привязке", frm.FPathLog);
                frmLogMessage.Dispose();

            }
            frm.Dispose();

        }

        private void tBtnUpdateRatingsFromDB_Click(object sender, EventArgs e)
        {
            // загрузка AMVInfo, если оно не загружено
            if (Gl.infoL.Count == 0) Gl.LoadAmvInfoList();

            // создание бекапа
            Backup.SaveBackup(Action.UpdateRatings);
            int cnt = 0;
            int cntChange = 0;
            for (int i = 0; i < Gl.DB.Count; i++)
            {
                if (Gl.DB[i].AMVNewsNum == -1 && Gl.DB[i].AkrossNum == -1 && Gl.DB[i].CreaConNum == -1) continue;

                bool bFind = false;
                bool bChange = false;
                foreach (AMVInfo aInf in Gl.infoL)
                {
                    if ((aInf.Site == SITE.AMVNews && Gl.DB[i].AMVNewsNum == aInf.Number)
                        || (aInf.Site == SITE.Akross && Gl.DB[i].AkrossNum == aInf.Number)
                        || (aInf.Site == SITE.CreaCon && Gl.DB[i].CreaConNum == aInf.Number))
                    {
                        if (Gl.DB[i].Sites[aInf.Site].LastUpdateRating == DateTime.MinValue || Gl.DB[i].Sites[aInf.Site].LastUpdateRating < aInf.GrabDate)
                        {
                            if (Gl.DB[i].Sites[aInf.Site].Rating != aInf.Rating) bChange = true;
                            Gl.DB[i].Sites[aInf.Site].Rating = aInf.Rating;
                            Gl.DB[i].Sites[aInf.Site].LastUpdateRating = aInf.GrabDate;
                        }
                        bFind = true;
                    }
                }
                if (bFind) cnt++;
                if (bChange) cntChange++;
            }

            ReFillAmv(true, true);
            Gl.DB.Save();
            MessageBox.Show(string.Format("Рейтинги успешно обновлены\r\nВсего найдено: {0}\r\nИз них изменены рейтинги у: {1}", cnt, cntChange));

        }

    }
}
